package com.augrain.microframework.web;

import com.augrain.microframework.core.consts.HttpStats;
import com.augrain.microframework.core.util.JSONUtils;
import com.augrain.microframework.core.util.SysUtils;
import com.augrain.microframework.trace.context.TraceContext;
import com.augrain.microframework.web.base.ApiContext;
import com.augrain.microframework.web.base.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.AnnotatedType;

/**
 * 将返回值用ApiResult封装后返回
 */
@Slf4j
@Order(0)
@ControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {

    private static final boolean hasTraceContext;

    static {
        hasTraceContext = SysUtils.isClassPresent("com.augrain.microframework.trace.context.TraceContext");
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class convertType) {
        return ApiContext.getCurrent() != null;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class convertType,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 自行处理过，或者被异常的advice已经处理过了
        if (body instanceof ApiResult) {
            ApiContext.current.remove();
            return body;
        }

        ApiContext current = ApiContext.getCurrent();
        if (current == null) {
            return body;
        }

        ApiResult apiResult = ApiResult.builder()
                .api(current.getApi())
                .data(body)
                .timestamp(System.currentTimeMillis())
                .sid(getTraceId())
                .code(HttpStats.HTTP_OK)
                .build();

        // 移除线程变量，防止线程复用造成污染
        ApiContext.current.remove();
        AnnotatedType annotatedReturnType = methodParameter.getExecutable().getAnnotatedReturnType();
        String typeName = annotatedReturnType.getType().getTypeName();

        if (String.class.getName().equals(typeName)) {
            serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=utf-8");
            return JSONUtils.toJson(apiResult);
        }
        return apiResult;
    }

    public String getTraceId() {
        if (hasTraceContext) {
            return TraceContext.getTraceId();
        }
        return null;
    }

}
